package com.tbit.uqbike.service.business.impl;

import com.tbit.common.enums.FeeTypeEnum;
import com.tbit.uqbike.constant.AccountConfigExtConstant;
import com.tbit.uqbike.constant.TimeFeeConstant;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.value.TimeFee;
import com.tbit.uqbike.service.business.TimeFeeService;
import com.tbit.uqbike.webmanager.dao.core.AccountConfigExtDao;
import com.tbit.uqbike.webmanager.dao.core.AddCountFeeDao;
import com.tbit.uqbike.webmanager.dao.core.TimeFeeDao;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chen
 * @Description:
 * @Date: 创建于 15:02 2023/11/2
 */
@Service
public class TimeFeeServiceImpl implements TimeFeeService {

    @Resource
    private TimeFeeDao timeFeeDao;
    @Resource
    private AddCountFeeDao addCountFeeDao;
    @Resource
    private AccountConfigExtDao accountConfigExtDao;

    @Override
    @Transactional
    public void add(TimeFeeVo timeFeeVo) {
        List<TimeFee> list = timeFeeVo.getList();
        check(list);

        AddCountFee addCountFee=null;
        if(timeFeeVo.getType().equals(TimeFeeConstant.TIMEFEE_VIPFEE)){
            addCountFee= addCountFeeDao.getByAccountId(timeFeeVo.getAccountId());
        }
        //先清除该类型分时计费重置成传递的数据
        deleteByType(timeFeeVo.getAccountId(),timeFeeVo.getType(),timeFeeVo.getAttachId());
        for (TimeFee timeFee : list) {
            if (Objects.nonNull(timeFee.getNoParkAreaMoney()) && timeFee.getNoParkAreaMoney() < 0 || timeFee.getNoParkAreaMoney() > 99900){
                throw new BaseException("请输入正确的金额");
            }
            timeFee.checkCapFee();
            timeFee.setAddTime(new Date());
            timeFee.setAccountId(timeFeeVo.getAccountId());
            timeFee.setType(timeFeeVo.getType());
            timeFee.setAttachId(timeFeeVo.getAttachId());
            if(addCountFee!=null){
                timeFee.setRechargeBase(addCountFee.getRechargeBase());
                timeFee.setFreeTime(addCountFee.getFreeTime());
                timeFee.setFreeRideTime(addCountFee.getFreeRideTime());
                timeFee.setNewUserFreeTime(addCountFee.getNewUserFreeTime());
                timeFee.setNewUserFreeTimes(addCountFee.getNewUserFreeTimes());
                timeFee.setNewUserRechcrge(addCountFee.getNewUserRechcrge());
                timeFee.setDispatchSwitch(addCountFee.getDispatchSwitch());
                timeFee.setAreaMoney(addCountFee.getAreaMoney());
                timeFee.setParkPointMoney(addCountFee.getParkPointMoney());
                timeFee.setHelmetSwitch(addCountFee.getHelmetSwitch());
                timeFee.setHelmetMoney(addCountFee.getHelmetMoney());
                timeFee.setNoParkAreaSwitch(addCountFee.getNoParkAreaSwitch());
                timeFee.setNoParkAreaMoney(addCountFee.getNoParkAreaMoney());
                timeFee.setFreeConditionType(addCountFee.getFreeConditionType());
                timeFee.setFreeDistance(addCountFee.getFreeDistance());
            }
            timeFeeDao.add(timeFee);
        }

    }

    /**
     * 校验是否重复
     *
     * @param timeFees
     */
    private void check(List<TimeFee> timeFees) {

        /**已经存在的数字*/
        List<Integer> existHour = new ArrayList<>();
        timeFees.forEach(x -> {
            if(x.getBeginTime()>=x.getEndTime()){
                throw new BaseException("beginTime.is.small");
            }
            if(x.getBeginTime()>24||x.getEndTime()>24||x.getBeginTime()<0||x.getEndTime()<0){
                throw new BaseException("beginTime.is.error");
            }
            for (int i = x.getBeginTime(); i < x.getEndTime(); i++) {
                existHour.add(i);
            }
        });
        Long num = existHour.stream().distinct().count();
        /**求交集*/
        if (num < existHour.size()) {
            throw new BaseException("timeFee.is.exist");
        }

    }


    @Override
    public void delete(Integer feeId) {
        timeFeeDao.delete(feeId);
    }

    @Override
    public List<TimeFee> getByAccountId(Integer accountId, Integer type,Integer feeId) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("type", type);
        map.put("attachId", feeId);
        return timeFeeDao.getByAccountId(map);
    }


    @Override
    public void deleteByType(Integer accountId, Integer type, Integer feeId) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("type", type);
        map.put("attachId", feeId);
        timeFeeDao.deleteByType(map);
    }

    @Override
    @Transactional
    public void addHolidayFee(HolidayFeeDto holidayFeeDto) {
        List<TimeFee> billHolidayList = holidayFeeDto.getBillHolidayList();
        // 规则重叠/合法性校验
        validDuplicateTime(billHolidayList);
        Integer accountId = -100;
        // 区域默认计费 addcountFee  和  区域分时计费 timeFee 兼容之前逻辑
        TimeFee timeFee = billHolidayList.stream().filter(x -> Objects.equals(x.getType(), TimeFeeConstant.HOLIDAY_AREA_FEE)).findFirst().orElse(null);
        List<TimeFee> areaTimeFees = billHolidayList.stream().filter(x -> Objects.equals(x.getType(), TimeFeeConstant.HOLIDAY_AREA_TIME_FEE)).map(x -> {
            TimeFee timeFee1 = new TimeFee();
            BeanUtils.copyProperties(x,timeFee1);
            timeFee1.setType(TimeFeeConstant.TIMEFEE_ACCOUNTFEE);
            return timeFee1;
        }).collect(Collectors.toList());
        billHolidayList.addAll(areaTimeFees);

        if (Objects.nonNull(timeFee)){
            AddCountFee addCountFee = new AddCountFee();
            BeanUtils.copyProperties(timeFee,addCountFee);
            addCountFeeDao.insert(addCountFee);
            accountId = addCountFee.getAccountId();
        }
        timeFeeDao.deleteByTypes(accountId);
        timeFeeDao.addBatch(billHolidayList);
    }

    /**
     * 计费时间段重复校验
     * @param billHolidayList 计费规则列表
     */
    private void validDuplicateTime(List<TimeFee> billHolidayList) {
        List<TimeFee> areaTimeList = billHolidayList.stream().filter(x -> Objects.equals(x.getType(), TimeFeeConstant.HOLIDAY_AREA_TIME_FEE)).collect(Collectors.toList());
        List<TimeFee> weekendTimeList = billHolidayList.stream().filter(x -> Objects.equals(x.getType(), TimeFeeConstant.HOLIDAY_WEEKEND_TIME_FEE)).collect(Collectors.toList());
        List<TimeFee> holidayTimeList = billHolidayList.stream().filter(x -> Objects.equals(x.getType(), TimeFeeConstant.HOLIDAY_TIME_FEE)).collect(Collectors.toList());
        // 区域分时计费
        if (!areaTimeList.isEmpty()){
            hasDuplicate(areaTimeList);
        }
        // 周末分时计费
        if (!weekendTimeList.isEmpty()){
            hasDuplicate(weekendTimeList);
        }
        // 节假日分时计费
        if (!holidayTimeList.isEmpty()){
            hasDuplicate(holidayTimeList);
        }
    }

    /**
     * 校验是否存在重复的时间
     * @param list 分时计费规则列表
     * @return 是否重复
     */
    private boolean hasDuplicate(List<TimeFee> list){
        Set<Integer> timeSet = new HashSet<>(24);
        for (TimeFee timeFee : list) {
            for (int i = timeFee.getBeginTime(); i < timeFee.getEndTime(); i++) {
                if (timeSet.contains(i)){
                    throw new BaseException("计费时间段重复");
                }
                timeSet.add(i);
            }
        }
        return true;
    }

    @Override
    public List<TimeFee> queryHoliday(Integer accountId) {
        List<TimeFee> timeFees = timeFeeDao.queryHoliday(accountId);
        return timeFees;
    }

    @Override
    public FeeTypeEnum queryFeeType(Integer accountId) {
        FeeTypeEnum res = FeeTypeEnum.NORMAL;
        // 查询区域所有配置
        List<AccountConfigExt> accountConfigExtList = accountConfigExtDao.getByAccountIdClass(accountId);
        // 分时计费是否启用判断
        boolean time_fee = accountConfigExtList.stream().anyMatch(x -> Objects.equals(x.getParamKey(), AccountConfigExtConstant.ACCOUNTCONFIG_TIMEOFUSEBILLING) && Objects.equals(x.getParamValue(), "1"));
        if (time_fee){
            res = FeeTypeEnum.TIME_FEE;
        }
        // 假日计费是否启用判断
        boolean holiday_fee = accountConfigExtList.stream().anyMatch(x -> Objects.equals(x.getParamKey(), AccountConfigExtConstant.HOLIDAY_FEE_SWITCH) && Objects.equals(x.getParamValue(), "1"));
        if (holiday_fee){
            res = FeeTypeEnum.HOLIDAY_FEE;
        }
        return res;
    }

    @Override
    @Transactional
    public void modifyFeeType(ModifyFeeTypeDto dto) {
        List<AccountConfigExt> accountConfigExtParamKeys = dto.getAccountConfigExtParamKey();
        List<String> keys = accountConfigExtParamKeys.stream().map(AccountConfigExt::getParamKey).collect(Collectors.toList());
        accountConfigExtDao.deleteByAccountIdAndKey(dto.getAccountId(),keys);
        accountConfigExtDao.addBatch(accountConfigExtParamKeys);
    }
}
